From dcb53c4965130cc88dd6b4a690155c643f8875eb Mon Sep 17 00:00:00 2001 From: Paul Donald Date: Tue, 18 Nov 2025 16:46:01 +0100 Subject: [PATCH] dhcpv6: assign a new field for prefix exclusion length MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit re-using the priority field is very confusing, for the sake of saving a byte. Signed-off-by: Paul Donald Link: https://github.com/openwrt/odhcp6c/pull/123 Signed-off-by: Álvaro Fernández Rojas --- src/dhcpv6.c | 43 +++++++++++++++++++++++-------------------- src/odhcp6c.h | 1 + src/script.c | 6 +++--- src/ubus.c | 6 +++--- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index a756971..5fbc437 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -787,8 +787,8 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs) continue; uint8_t ex_len = 0; - if (pd_entries[j].priority > 0) - ex_len = ((pd_entries[j].priority - pd_entries[j].length - 1) / 8) + 6; + if (pd_entries[j].exclusion_length > 0) + ex_len = ((pd_entries[j].exclusion_length - pd_entries[j].length - 1) / 8) + 6; struct dhcpv6_ia_prefix p = { .type = htons(DHCPV6_OPT_IA_PREFIX), @@ -810,11 +810,11 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs) ia_pd[ia_pd_len++] = DHCPV6_OPT_PD_EXCLUDE; ia_pd[ia_pd_len++] = 0; ia_pd[ia_pd_len++] = ex_len - DHCPV6_OPT_HDR_SIZE; - ia_pd[ia_pd_len++] = pd_entries[j].priority; + ia_pd[ia_pd_len++] = pd_entries[j].exclusion_length; uint32_t excl = ntohl(pd_entries[j].router.s6_addr32[1]); - excl >>= (64 - pd_entries[j].priority); - excl <<= 8 - ((pd_entries[j].priority - pd_entries[j].length) % 8); + excl >>= (64 - pd_entries[j].exclusion_length); + excl <<= 8 - ((pd_entries[j].exclusion_length - pd_entries[j].length) % 8); for (size_t k = ex_len - 5; k > 0; --k, excl >>= 8) ia_pd[ia_pd_len + k] = excl & 0xff; @@ -1666,6 +1666,7 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret) .auxlen = 0, .length = 0, .ra_flags = 0, + .exclusion_length = 0, .target = IN6ADDR_ANY_INIT, .priority = 0, .valid = 0, @@ -1721,33 +1722,35 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret) if (ret) *ret = 0; // renewal failed } else if (stype == DHCPV6_OPT_PD_EXCLUDE && slen > 2) { /* RFC 6603 §4.2 Prefix Exclude option */ - uint8_t elen = sdata[0]; - if (elen > 64) - elen = 64; + uint8_t exclude_length = sdata[0]; + if (exclude_length > 64) + exclude_length = 64; - if (entry.length < 32 || elen <= entry.length) { + if (entry.length < 32 || exclude_length <= entry.length) { update_state = false; continue; } - uint8_t bytes = ((elen - entry.length - 1) / 8) + 1; - if (slen <= bytes) { + uint8_t bytes_needed = ((exclude_length - entry.length - 1) / 8) + 1; + if (slen <= bytes_needed) { update_state = false; continue; } - uint32_t exclude = 0; + // this decrements through the ipaddr bytes masking against + // the address in the option until byte 0, the option length field. + uint32_t excluded_bits = 0; do { - exclude = exclude << 8 | sdata[bytes]; - } while (--bytes); + excluded_bits = excluded_bits << 8 | sdata[bytes_needed]; + } while (--bytes_needed); - exclude >>= 8 - ((elen - entry.length) % 8); - exclude <<= 64 - elen; + excluded_bits >>= 8 - ((exclude_length - entry.length) % 8); + excluded_bits <<= 64 - exclude_length; - // Abusing router & priority fields for exclusion - entry.router = entry.target; - entry.router.s6_addr32[1] |= htonl(exclude); - entry.priority = elen; + // Re-using router field to hold the prefix + entry.router = entry.target; // base prefix + entry.router.s6_addr32[1] |= htonl(excluded_bits); + entry.exclusion_length = exclude_length; } } diff --git a/src/odhcp6c.h b/src/odhcp6c.h index 410da1e..b0094fe 100644 --- a/src/odhcp6c.h +++ b/src/odhcp6c.h @@ -482,6 +482,7 @@ struct odhcp6c_entry { uint8_t auxlen; uint8_t length; uint8_t ra_flags; + uint8_t exclusion_length; struct in6_addr target; int16_t priority; uint32_t valid; diff --git a/src/script.c b/src/script.c index 131d70d..10c3482 100644 --- a/src/script.c +++ b/src/script.c @@ -217,13 +217,13 @@ static void entry_to_env(const char *name, const void *data, size_t len, enum en buf_len += strlen(&buf[buf_len]); } - if (type == ENTRY_PREFIX && e[i].priority) { - // priority and router are abused for prefix exclusion + if (type == ENTRY_PREFIX && e[i].exclusion_length) { snprintf(&buf[buf_len], 11, ",excluded="); buf_len += strlen(&buf[buf_len]); + // '.router' is dual-used: for prefixes it contains the prefix inet_ntop(AF_INET6, &e[i].router, &buf[buf_len], INET6_ADDRSTRLEN); buf_len += strlen(&buf[buf_len]); - snprintf(&buf[buf_len], 12, "/%u", e[i].priority); + snprintf(&buf[buf_len], 12, "/%u", e[i].exclusion_length); buf_len += strlen(&buf[buf_len]); } } diff --git a/src/ubus.c b/src/ubus.c index 0b37ddf..664feff 100644 --- a/src/ubus.c +++ b/src/ubus.c @@ -343,13 +343,13 @@ static int entry_to_blob(const char *name, const void *data, size_t len, enum en blobmsg_add_u32(&b, "iaid", ntohl(e[i].iaid)); } - if (type == ENTRY_PREFIX && e[i].priority) { - // priority and router are abused for prefix exclusion + if (type == ENTRY_PREFIX && e[i].exclusion_length) { buf = blobmsg_alloc_string_buffer(&b, "excluded", INET6_ADDRSTRLEN); CHECK_ALLOC(buf); + // '.router' is dual-used: for prefixes it contains the prefix inet_ntop(AF_INET6, &e[i].router, buf, INET6_ADDRSTRLEN); blobmsg_add_string_buffer(&b); - blobmsg_add_u32(&b, "excluded_length", e[i].priority); + blobmsg_add_u32(&b, "excluded_length", e[i].exclusion_length); } } -- 2.30.2